home *** CD-ROM | disk | FTP | other *** search
- [ Cracking Level-2 Making Your First Key Generator ]
- =====================================================
-
- First off, there are two ways to make a key generator. First type
- is to copy the entire assembly code, modify it a little to make it
- produce the key, and compile it using an assembler. In this case
- you'll only need to know where the registration code starts, where
- it ends, and what are its variables. Second type is to analysis
- the entire registration routine, and translate/modified it into a
- higher level language, and compile it using high level language
- compiler. This will take a little bit longer, but I perfer to write
- key makers this way. As it is how I write all my other key makers.
-
- Below is a main portion of the Level-2 registration routine obtained
- from W32Dasm. I have heavily commented the code to make things clear
- and to help you learn Assembly language along the way.
-
- Go break into the program, set a break point on GetDlgItemTextA
- And once you're in press [F12] to get out from USER32 and MFC42, until
- you get back into CrackMe's instruction codes. Once you're in
- CrackMe, try and get to the first line [F10] shown below (:00401ADF).
- Note that you might still have the break point on GetDlgItemTextA, so
- you might want to disable that before stepping trought the codes.
- "d *" is the command to disable all break points in Softice.
-
- ----------------------------------------------------------------------
- :00401ADF E8FA100000 Call 00402BDE ; MFC42.GetDlgItemTextA
- :00401AE4 8D4C247C lea ecx, dword ptr [esp+7C]
- :00401AE8 6A33 push 00000033
- :00401AEA 51 push ecx
- :00401AEB 68ED030000 push 000003ED
- :00401AF0 8BCB mov ecx, ebx
- :00401AF2 E8E7100000 Call 00402BDE ; MFC42.GetDlgItemTextA (get username)
- :00401AF7 8D542414 lea edx, dword ptr [esp+14] ; -> points to username
- :00401AFB 52 push edx ; -> push username on stack for lstrlenA
- :00401AFC FF1500404000 Call dword ptr [00404000] ; KERNEL32.lstrlenA
- :00401B02 8BF0 mov esi, eax ; save string length to esi
- :00401B04 83FE05 cmp esi, 00000005 ; is string length < 5 ?
- :00401B07 7311 jnb 00401B1A ; jump/good name if length is >= 5
- :00401B09 6A40 push 00000040
- :00401B0B 6804514000 push 00405104
- :00401B10 68D8504000 push 004050D8
- :00401B15 E9BA000000 jmp 00401BD4 ; jump/quit to show end MessageBox
-
- :00401B1A B801000000 mov eax, 00000001 ; set eax to 1 (counter)
- :00401B1F 33FF xor edi, edi ; set edi to 0
- :00401B21 3BF0 cmp esi, eax ; (esi - eax)
- :00401B23 7211 jb 00401B36 ; jump if esi(length) < eax;
-
- ; [esp+14] points to the username
- ; eax is the counter
- :00401B25 0FBE4C0414 movsx ecx, byte ptr [esp+eax+14] ; ecx = user[eax]
- :00401B2A 03CF add ecx, edi ; ecx = ecx + edi
- :00401B2C 0FAFC8 imul ecx, eax ; ecx = ecx * eax
- :00401B2F 40 inc eax ; eax = eax + 1
- :00401B30 8BF9 mov edi, ecx ; edi = ecx
- :00401B32 3BC6 cmp eax, esi ; (eax - esi) (eax is the counter)
- :00401B34 76EF jbe 00401B25 ; loop if eax <= esi(length)
-
- :00401B36 33C9 xor ecx, ecx ; ecx = 0;
- :00401B38 85F6 test esi, esi ; (esi & esi)
- :00401B3A 7620 jbe 00401B5C ; jump/quit if esi(length) is 0
-
- ; [esp+14] points to the username
- ; [esp+48] points to the generated key
- ; ecx is the counter = 0 at start
- ; edi contains a key value from previous loop
- :00401B3C 0FBE6C0C14 movsx ebp, byte ptr [esp+ecx+14] ; ebp = user[ecx]
- :00401B41 8BC7 mov eax, edi ; eax = edi (key)
- :00401B43 33D2 xor edx, edx ; edx = 0
- :00401B45 F7F5 div ebp ; eax = eax/ebp, edx = eax%ebp
- :00401B47 33D2 xor edx, edx ; edx = 0
- :00401B49 BD0A000000 mov ebp, 0000000A ; ebp = 0xA
- :00401B4E F7F5 div ebp ; eax = eax/ebp, edx = eax%ebp
- :00401B50 80C230 add dl, 30 ; dl = dl + 0x30
- :00401B53 88540C48 mov byte ptr [esp+ecx+48], dl ; key[ecx] = dl
- :00401B57 41 inc ecx ; ecx = ecx + 1
- :00401B58 3BCE cmp ecx, esi ; (ecx - esi)
- :00401B5A 72E0 jb 00401B3C ; loop if ecx < esi
-
- :00401B5C 8D542448 lea edx, dword ptr [esp+48] ; -> generated key
- :00401B60 8D44247C lea eax, dword ptr [esp+7C] ; -> password entered
- :00401B64 52 push edx ; push pointer to key onto stack
- :00401B65 50 push eax ; push pointer to password onto stack
- ; lstrcmpA compares the two string pushed onto stack
- ; the return value is stored in eax
- ; if two string equals, eax = 0
- :00401B66 FF1508404000 Call dword ptr [00404008] ; KERNEL32.lstrcmpA
- :00401B6C 85C0 test eax, eax ; (eax & eax)
- :00401B6E 7550 jne 00401BC0 ; jump if eax is not 0
-
-
- Now without looking at the solution, see if you can translate the above
- assembly code into a high level pseudo code. Then compare the pseudo code
- to the actually codes (solution) below. Just to give you an idea of what
- I mean by pseudo code, lets take a look at line :00401B25 to :00401B34
- for an example.
- First off this is obviously a loop, because of the "JBE" instruction at
- line :00401B34. This tells it to jump back to line :00401B25. But what
- are the conditions for this loop? Well, lets start from the beginning...
-
- Start of code Anaylsis:
- This is the first line of the loop...
- :00401B25 0FBE4C0414 movsx ecx, byte ptr [esp+eax+14]
- You know that mov is just the same as '=' sign in high level language.
- And movsx is just a variant of mov, and the distinction between the two
- is not important here. What you need to know is what this line of
- instruction is doing. And when you see the bracket [], you know it's got
- something to do with the memory. So you should spy on the memory a little
- and see what's up. Just type in "d esp+eax+14" at Softice command window.
- All of a sudden you should see your username in the data window. So
- obviously the above instruction is moving a character (byte) from the
- username into the ECX register!
-
- Now lets look at the rest of the loop's content:
- (note that EAX was initialized to 1 at line :00401B1A)
- (also note that EDI was initialized to 0 at line :00401B1F)
-
- add ecx, edi ; add edi to ECX (ecx is the byte from username)
- imul ecx, eax ; multiply ECX by eax (eax is the counter for this loop)
- inc eax ; add one to EAX
- mov edi, ecx ; save ecx to EDI (secret value!!!)
- cmp eax, esi ; it modifies the zero & sign flag for comparison
- jbe 00401B25 ; loop if eax <= esi (esi is the length of the username)
-
- The last two lines obviously tells you that EAX is indeed the counter.
- Because it is used to compare against ESI, which is the length of the
- username. And how do you know that EDI stores the secret value?
- Well, you know it is not eax or esi. You also know that it is not
- ecx, because ecx is changed at the first line when you move bytes from
- username to it. And all you left with is edi, and it only involves in
- mathmatical operations. So edi must be it! The final value return/result
- from this loop!
- Also noticed that EAX gets incremented! This is use to move the character
- pointer along the string. Each loop, this counter will points to the
- next character in the string.
-
- Now you have enough information to write your first pseudo code!
-
- i = 1
- finalvalue = 0
-
- do
- tmpvar = username(i)
- tmpvar = tmpvar * i
- i = i + 1
- finalvalue = tmpvar
- repeat if i <= length of username
-
- You are done! The only thing left is to do the same with the rest of
- the registration routine, and then translate the pseudo codes into
- higher level language that you're familiar with, and modify the code
- a little to make it produce the registration key!
-
-
- Solution to the registration routine taken from my C++ source file.
- -------------------------------------------------------------------
- register DWORD i, slen, sum;
- char usrn[51] = "\0", key[51] = "\0", keystr[51] = "\0";
-
- GetDlgItemText(IDC_USRN, usrn, 51);
- GetDlgItemText(IDC_KEY, key, 51);
- if ((slen = lstrlen(usrn)) < 5)
- {
- MessageBox("User Name must have at least 5 characters.",
- "CrackMe", MB_OK | MB_ICONINFORMATION);
- return;
- }
- for (sum = 0, i = 1; i <= slen; i++)
- {
- sum += usrn[i];
- sum *= i;
- }
- for (i = 0; i < slen; i++)
- keystr[i] = LOBYTE( (sum / usrn[i]) % 10 + '0' );
- if (lstrcmp(key, keystr) == 0)
- {
- // correct registration code!
- }
- else
- {
- // incorrect registration code!
- }
-
- Sample of Key Generator
- -----------------------
- This is all you will need for the key generator, after translation.
- All you need to do is to display "keystr[]" to the user.
- There isn't much for you to modified from the original code in order
- to obtain the registration key. You bascially just need to port
- part of the code and remove the remaining, and that's it.
-
- for (sum = 0, i = 1; i <= slen; i++)
- {
- sum += usrn[i];
- sum *= i;
- }
- for (i = 0; i < slen; i++)
- keystr[i] = LOBYTE( (sum / usrn[i]) % 10 + '0' );
-